package com.easy.framework.common.config;

import lombok.Getter;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

@Log4j2
@Setter
@Getter
@EnableAsync
@Configuration
@ConfigurationProperties(prefix = "easy.async")
public class AsyncConfig implements AsyncConfigurer , DisposableBean {

    private int corePoolSize=10;

    private int maxPoolSize=20;

    private int queueCapacity=100;

    private int ioCorePoolSize=20;

    private int ioMaxPoolSize=50;

    private int ioQueueCapacity=200;


    private ThreadPoolTaskExecutor taskExecutor;
    private ThreadPoolTaskExecutor ioTaskExecutor;

    @Override
    @Bean(name = "taskExecutor")
    public Executor getAsyncExecutor() {
        taskExecutor = new ThreadPoolTaskExecutor();
        taskExecutor.setCorePoolSize(corePoolSize);
        taskExecutor.setMaxPoolSize(maxPoolSize);
        taskExecutor.setQueueCapacity(queueCapacity);
        taskExecutor.setThreadNamePrefix("Async-Executor-");
        taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        taskExecutor.setWaitForTasksToCompleteOnShutdown(true);// 等待任务完成
        taskExecutor.setAwaitTerminationSeconds(30);// 最多等待30秒
        taskExecutor.initialize();
        return taskExecutor;

    }

    @Bean(name = "ioTaskExecutor")
    public Executor ioTaskExecutor() {
        ioTaskExecutor = new ThreadPoolTaskExecutor();
        ioTaskExecutor.setCorePoolSize(ioCorePoolSize);
        ioTaskExecutor.setMaxPoolSize(ioMaxPoolSize);
        ioTaskExecutor.setQueueCapacity(ioQueueCapacity);
        ioTaskExecutor.setThreadNamePrefix("IO-Executor-");
        ioTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        ioTaskExecutor.initialize();
        return ioTaskExecutor;
    }


    @Override
    public void destroy() throws Exception {
        shutdownExecutor(taskExecutor, "Async-Executor");
        shutdownExecutor(ioTaskExecutor, "IO-Executor");
    }

    private void shutdownExecutor(ThreadPoolTaskExecutor executor, String name) {
        if (executor != null) {
            log.info("Shutting down {} thread pool", name);
            executor.shutdown();
            try {
                if (!executor.getThreadPoolExecutor().awaitTermination(30, TimeUnit.SECONDS)) {
                    log.warn("{} thread pool did not terminate gracefully within 30 seconds", name);
                    executor.getThreadPoolExecutor().shutdownNow();
                }
            } catch (InterruptedException e) {
                log.warn("Interrupted while waiting for {} thread pool to shutdown", name, e);
                executor.getThreadPoolExecutor().shutdownNow();
                Thread.currentThread().interrupt();
            }
        }
    }
}
